home *** CD-ROM | disk | FTP | other *** search
/ Aminet 7 / Aminet 7 - August 1995.iso / Aminet / comm / tcp / AmigaTCP.lha / AmigaTCP / src / smtpcli.c < prev    next >
C/C++ Source or Header  |  1989-06-24  |  8KB  |  307 lines

  1. /* smtpcli.c
  2.  *    Client routines for Simple Mail Transfer Protocol ala RFC821
  3.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  4.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  5.  *    Permission granted for non-commercial copying and use, provided
  6.  *    this notice is retained.
  7.  */
  8.  
  9. #include <stdio.h>
  10. #include "machdep.h"
  11. #include "netuser.h"
  12. #include "mbuf.h"
  13. #include "timer.h"
  14. #include "tcp.h"
  15. #include "smtp.h"
  16.  
  17. extern int16 lport;            /* local port placeholder */
  18. int32 aton();
  19. static void sendit();
  20. static struct timer smtpcli_t;
  21. char *index(),*rindex();
  22.  
  23. /* init routine called when program fired up */
  24. smtpclinit()
  25. {
  26.     int dosmtptick();
  27.  
  28.     smtpcli_t.func = (void (*)())dosmtptick;/* what to call on timeout */
  29.     smtpcli_t.arg = 0;            /* dummy value */
  30.     smtpcli_t.start = SMTPCLITIME;        /* set timer duration */
  31.     start_timer(&smtpcli_t);        /* and fire it up */
  32. }
  33.  
  34. /* this is the routine that gets called every so often to do outgoing mail
  35.    processing */
  36. int
  37. dosmtptick()
  38. {
  39.     char     lfilename[LINELEN],
  40.         tmpstring[LINELEN],
  41.         wfilename[13],
  42.         *ptr;
  43.     FILE *lfile;
  44.     struct smtp_msg *mp;
  45.     struct socket lsocket, fsocket;
  46.     char *calloc(),*malloc();
  47.     void smtp_rec(), smtp_cts(), smtp_state();
  48.  
  49. /*    printf("DOSMTPTICK() entered\n");    */
  50.     lsocket.address = ip_addr;    /* our ip address */
  51.     fsocket.port = SMTP_PORT;
  52. /* if lock file exists in mqueue dir, return */
  53.     sprintf(lfilename,"%s%s",MAILQDIR,"lockfile");
  54.     if ((lfile = fopen(lfilename,"x")) == NULL)
  55.         return;
  56. /* get next work filename from mqueue directory */
  57.     sprintf(tmpstring,"%s%s",MAILQDIR,"*.wrk");
  58. #ifndef    AMIGA
  59.     filedir(tmpstring,0,wfilename);
  60. #endif
  61.     if (wfilename[0] == '\0')
  62.         return;    /* no work to be done */
  63. /* if we have work, rebuild the exact (non-wild) filename */
  64.     mp = (struct smtp_msg *)calloc(1,sizeof (struct smtp_msg));
  65.     sprintf(tmpstring,"%s%s",MAILQDIR,wfilename);
  66.     ptr = &tmpstring[0];
  67.     mp->filename = malloc((unsigned)strlen(ptr)+1);
  68.     strcpy(mp->filename,ptr);
  69. /*    printf("work file name: %s\n",mp->filename);    /* debug only */
  70.     mp->wfile = fopen(mp->filename,"r");
  71. /*   get ip address, from stuff, to stuff */
  72.     fgets(tmpstring,LINELEN,mp->wfile);    /* read target ip addr */
  73. /*    printf("target ip addr: %s\n",tmpstring);    */
  74.     fgets(mp->toaddr,LINELEN,mp->wfile);        /* who to */
  75.     rip(mp->toaddr);
  76. /*    printf("addressee: %s\n",mp->toaddr);        */
  77.     fgets(mp->fromaddr,LINELEN,mp->wfile);        /* who from */
  78.     rip(mp->fromaddr);
  79. /*    printf("sender: %s\n",mp->fromaddr);        */
  80.     fclose(mp->wfile);
  81. /* set up the rest of the socket info from what we got */
  82.     fsocket.address = aton(tmpstring);    /* destination ip address */
  83.     lsocket.port = lport++;            /* next unused port */
  84. /*   open smtp connection */
  85.     mp->state = CLI_OPEN_STATE;        /* init state placeholder */
  86. /*    printf("Opening TCP connection for SMTP client\n");    */
  87.     mp->tcb = open_tcp(&lsocket,&fsocket,TCP_ACTIVE,1024,
  88.             smtp_rec,smtp_cts,smtp_state,0,(int *)mp);
  89.     mp->tcb->user = (int *)mp;        /* Upward pointer */
  90.  
  91. /*    printf("releasing lock\n");        */
  92.     if (lfile != NULL) {            /* release lock */
  93.         fclose(lfile);
  94.         unlink(lfilename);
  95.     }
  96. }
  97.  
  98. /* replace terminating end of line marker(s) with null */
  99. rip(s)
  100. char *s;
  101. {
  102.     char *c;
  103.  
  104.     c=s;
  105.     while (*c != '\0') {
  106.         switch (*c) {
  107.         case '\r':
  108.         case '\n':
  109.             *c='\0';
  110.             break;
  111.         default:
  112.             c++;
  113.             break;
  114.         }
  115.     }
  116. }
  117.  
  118. /* this is the master state machine that handles a single SMTP transaction */
  119. smtp_transaction(mp)
  120. struct smtp_msg *mp;
  121. {
  122.     char tmpstring[LINELEN];    /* where we build command lines */
  123.  
  124. /*    printf("SMTP_TRANSACTION() called, state=%u\n",mp->state);    */
  125.     if (affirmative(mp)) {
  126.         switch(mp->state) {
  127.         case CLI_OPEN_STATE:
  128.             mp->state = CLI_MAIL_STATE;
  129.             /* issue MAIL command */
  130. /*            printf("FROMADDR = %s\n",mp->fromaddr);        */
  131.             sprintf(tmpstring,"mail from:<%s>\r\n",mp->fromaddr);
  132.             sendit(mp,tmpstring);
  133.             break;            
  134.         case CLI_MAIL_STATE:
  135.             mp->state = CLI_RCPT_STATE;
  136.             /* issue RCPT command */
  137.             sprintf(tmpstring,"rcpt to:<%s>\r\n",mp->toaddr);
  138.             sendit(mp,tmpstring);
  139.             break;
  140.         case CLI_RCPT_STATE:
  141.             mp->state = CLI_SEND_STATE;
  142.             /* open text file */
  143.             strcpy(tmpstring,mp->filename);
  144.             strcpy(index(tmpstring,'.'),".txt");
  145. /*            printf("text filename: %s",tmpstring);        */
  146.             mp->tfile = fopen(tmpstring,"r");
  147.             /* issue DATA command */
  148.             sprintf(tmpstring,"data\r\n");
  149.             sendit(mp,tmpstring);
  150.             break;
  151.         case CLI_SEND_STATE:
  152.             /* the transmitter upcall routine will advance the
  153.                state pointer on end of file, so we do nada... */
  154.             break;
  155.         case CLI_UNLK_STATE:
  156.             unlink(mp->filename);    /* unlink workfile */
  157.             /* close and unlink the textfile */
  158.             fclose(mp->tfile);
  159.             strcpy(tmpstring,mp->filename);
  160.             strcpy(index(tmpstring,'.'),".txt");
  161.             unlink(tmpstring);
  162.             mp->state = CLI_QUIT_STATE;
  163.             /* issue a quit command */
  164.             sprintf(tmpstring,"quit\r\n");
  165.             sendit(mp,tmpstring);
  166.             break;
  167.         case CLI_QUIT_STATE:
  168.             /* either start next transaction, or quit */
  169.             close_tcp(mp->tcb);    /* close up connection */
  170.             break;
  171.         }
  172.     } else {    /* if we get here, means we got a negative reply */
  173.             /* for the moment, just let that hose us... */
  174.         mp->state = CLI_QUIT_STATE;
  175.         /* issue a quit command */
  176.         sprintf(tmpstring,"quit\r\n");
  177.         sendit(mp,tmpstring);
  178.     }
  179. }
  180.  
  181. /* return true if the passed string contains a positive response code */
  182. affirmative(mp)
  183. struct smtp_msg *mp;
  184. {
  185.     /* 2 is always good, 3 is ok if we've just sent 'data' command */
  186.     if ((*mp->buf = '2') || 
  187.            ((*mp->buf = '3') && (mp->state = CLI_DATA_STATE)))
  188.         return 1;
  189.     else     return 0;
  190. }
  191.  
  192. /* smtp receiver upcall routine.  fires up the state machine to parse input */
  193. static
  194. void
  195. smtp_rec(tcb,cnt)
  196. struct tcb *tcb;
  197. int16 cnt;
  198. {
  199.     register struct smtp_msg *mp;
  200.     char *inet_ntoa(), c;
  201.     struct mbuf *bp;
  202.     /* may want a void line here for procedures used */
  203.  
  204. /*    printf("SMTP_REC called\n");        */
  205.     mp = (struct smtp_msg *)tcb->user;    /* point to our struct */
  206.     recv_tcp(tcb,&bp,cnt);    /* suck up chars from low level routine */
  207.  
  208.     /* Assemble input line in buffer, return if incomplete */
  209.     while(pullup(&bp,&c,1) == 1) {
  210.         switch(c) {
  211.         case '\r':    /* strip cr's */
  212.             continue;
  213.         case '\n':    /* line is finished, go do it! */
  214.             mp->buf[mp->cnt] = '\0';
  215.             smtp_transaction(mp);
  216.             break;
  217.         default:    /* other chars get added to buffer */
  218.             mp->buf[mp->cnt++] = c;
  219.             break;
  220.         }
  221.     }
  222. }
  223.  
  224. /* smtp transmitter ready upcall routine.  twiddles cts flag */
  225. static 
  226. void
  227. smtp_cts(tcb,cnt)
  228. struct tcb *tcb;
  229. int16 cnt;
  230. {
  231.     register struct smtp_msg *mp;
  232.     struct mbuf *bp;
  233.     char tmpstring[LINELEN];
  234.     char *cp;
  235.     int c;
  236.  
  237. /*    printf("SMTP_CTS called\n");        */
  238.     mp = (struct smtp_msg *)tcb->user;    /* point to our struct */
  239.  
  240.     /* don't do anything until/unless we're supposed to be sending */
  241.     if(mp->state != CLI_SEND_STATE) return;
  242.  
  243.     if((bp = alloc_mbuf(cnt)) == NULLBUF){
  244.         /* Hard to know what to do here */
  245.         return;
  246.     }
  247.     cp = bp->data;
  248.     while(cnt > 1 && (c = getc(mp->tfile)) != EOF){
  249.         *cp++ = c;
  250.         bp->cnt++;
  251.         cnt--;
  252.     }
  253.     if(bp->cnt != 0)
  254.         send_tcp(tcb,bp);
  255.     else
  256.         free_p(bp);
  257.  
  258.     if(cnt > 1){    /* EOF seen */
  259.         sprintf(tmpstring,"\r\n.\r\n");
  260.         sendit(mp,tmpstring);
  261.         mp->state = CLI_UNLK_STATE;
  262.     }
  263. }
  264.  
  265. /* smtp state change upcall routine.  cans connection on error */
  266. static
  267. void
  268. smtp_state(tcb,old,new)
  269. struct tcb *tcb;
  270. char old,new;
  271. {
  272.     struct smtp_msg *mp;
  273.  
  274. /*    printf("SMTP_STATE called, state=%u\n",new);    */
  275.     mp = (struct smtp_msg *)tcb->user;
  276.     switch(new) {
  277.     case ESTABLISHED:
  278.         mp->state = CLI_OPEN_STATE;    /* shouldn't be needed */
  279.         break;
  280.     case CLOSE_WAIT:
  281.         close_tcp(tcb);            /* shut things down */
  282.             /* may want to do something here to shut down
  283.                the rest of the transaction? */
  284.         break;
  285.     case CLOSED:
  286.         del_tcp(tcb);            /* hosed for good */
  287.         if(mp->filename != NULLCHAR)
  288.             free(mp->filename);
  289.         free((char *)mp);
  290.         break;
  291.     }
  292. }
  293.  
  294. /* Send message back to server */
  295. static
  296. void
  297. sendit(mp,message)
  298. struct smtp_msg *mp;
  299. char *message;
  300. {
  301.     struct mbuf *bp,*qdata();
  302.  
  303. /*    printf("SENDIT called: %s",message);        */
  304.     bp = qdata(message,(int16)strlen(message));
  305.     send_tcp(mp->tcb,bp);
  306. }
  307.